#用于arxml的生成工具的定义文件，提供给pares和generator定义参数名
#UAES-Qiyao                              初次生成：2023-08-24

#SWC文件树
#|-SoftwareTypes
#|  |-Interfaces
#|  |-ComponentTypes
#|-DataTypes
#|  |-ImplementationDataTypes
#|  |-CompuMethods
#|  |-DataConstraints
#|  |-ApplicationDataTypes
#|-DataTypeMappingSets
#|  |-Data_Type_Mappings
#|-UAES_Platform
#|  |-SwBaseTypes
import logging, logging.handlers
import openpyxl,openpyxl.worksheet.worksheet
import copy
import os

#命名规则类
class name_def():
    #设置保存文件位置
    root='./ARXMLS/'
    #基础类型定义
    base_types={
        'uint8':[8,None,'unsigned char','FIXED_LENGTH'],
        'uint16':[16,None,'unsigned short','FIXED_LENGTH'],
        'int16':[16,None,'signed short','FIXED_LENGTH'],
    }
    #表格命名方式定义
    Struct_name='Struct'
    Int_name='Integer'
    Array_name='Array'
    Array_size_name='String/Array Length Max'
    Enum_name='Enumeration'
    Member_data_ref='Member Datatype Reference'
    #方法命名方法定义
    getter='Getter'
    setter='Setter'
    RR_method='R/R Method'
    Event='Event'
    Field='Field'
    Field_ntf='Notification Event'
    #field下面名字一致情况的命名方法
    def opt_get_name(opt_name:str)->str:
        return 'get'+'_'+opt_name
    def opt_set_name(opt_name:str)->str:
        return 'set'+'_'+opt_name
    #Excel表内sheet的命名
    sheet_names={
        'server':'1 服务定义',
        'datatype':'2 数据类型定义',
        'mapping':'mapping_info',
    }

    #首字母大写函数
    def big_one(name:str)->str:
        a=name[0]
        res=a.upper()+name[1:]
        return res
    #IDT索引basetype用
    def IDT_base_ref(swc:str,name:str)->str:
        return '/%s/UAES_Platform/SwBaseTypes/'%name_def.swc_pkg_name(swc)+name
    #IDT命名规则
    def IDT_fmt(name:str)->str:
        return 'IDT_'+name
    #ADT命名规则
    def ADT_PRM_fmt(name:str)->str:
        return 'ADT_'+name
    #admindata生成函数
    def create_admindata(length):
        admin={'SDG_GID':"SOA-SERVICE",
                    'SD_GID':"LENGTH",
                    'SD':length}
        return admin
    
    def swc_pkg_name(swc_name:str,timeperiod=10):
        return swc_name
    #IDT ref生成
    def IDT_ref_addr(swc:str,name:str)->str:
        return '/%s/DataTypes/ImplementationDataTypes/IDT_'%name_def.swc_pkg_name(swc)+name
    #ADT ref生成
    def ADT_ref_addr(swc:str,name:str)->str:
        return '/%s/DataTypes/ApplicationDataTypes/ADT_'%name_def.swc_pkg_name(swc)+name
    def ADT_DTE_fmt(name:str)->str:
        return 'DTE_'+name
    #ADT compute method ref生成
    def ADT_CM_ref_addr(swc:str,name:str)->str:
        return '/%s/DataTypes/CompuMethods/CM_'%name_def.swc_pkg_name(swc)+name
    #ADT data constraint ref生成
    def ADT_DC_ref_addr(swc:str,name:str)->str:
        return '/%s/DataTypes/DataConstraints/DC_'%name_def.swc_pkg_name(swc)+name
    ####interface命名格式
    def Interface_name(swc_name:str,interface_name:str)->str:
        return interface_name
    #SWC命名方法
    def SWC_name_formate(name:str)->str:
        return name
    def SWC_comp_name_formate(name:str)->str:
        return name
    def CS_port_name(swc:str):
        return swc+'_Provide'
    #behavior命名方法
    def Behavior_name_formate(name:str)->str:
        return name+'_Behavior'
    #port命名方法
    def Port_name_formate(service_name:str,port_name:str)->str:
        #name = service_name + '_' + port_name######CA port命名格式
        return port_name
    #interface 命名方法
    def Interface_name_formate(service_name:str,interface_name:str)->str:
        #name = service_name + '_' + interface_name######CA interface命名格式
        return interface_name
    def Interface_name_RR(service_name:str)->str:
        return service_name
    #runnable命名方法
    def Runnable_name_formate(service_name,interface_name):
        name = service_name + '_' + interface_name######CA runnable命名格式
        return name
    #####runnable_init命名格式
    def Runnable_init_formate(service_name):
        name = service_name + '_Init'
        return name
    #####runnable_time命名格式
    def Runnable_time_formate(service_name,time):
        name = 'TMT' + str(time) + 'ms_' + service_name
        return name
    #####init_event命名格式
    def Init_event_formate(service_name):
        name = 'Event_' + service_name + '_Init'
        return name
    #####time_event命名格式
    def Time_event_formate(service_name,time):
        name = 'Event_' + 'TMT' + str(time) + 'ms_' + service_name
        return name
    #opt 命名方法
    def Operation_ref_formate(port_name,name:str)->str:
        str1=port_name+'/'+name
        return  str1
    
def combine_dict(dict1:dict,dict2:dict)->dict:
    temp_dict={}
    temp_list1=[]
    temp_list2=[]
    for i in dict1:
        temp_list1=dict1[i]
        if dict2.get(i)!=None:
            temp_list2=dict2[i]
        temp_list=list(set(temp_list1+temp_list2))
        temp_dict.update({i:temp_list})
    return temp_dict


class Log():
    __instance__ = None
    # 设置日志文件的存放目录
    log_dir = 'log'
    # 设置日志文件的名字
    log_filename = 'transform.log'
    # 日志格式化输出
    LOG_FORMAT = "%(asctime)s - %(levelname)s: %(message)s"
    # 日期格式
    DATE_FORMAT = "%Y-%m-%d %H:%M:%S %p"
    log_dir = os.path.abspath('') + '\\' + log_dir
    if not os.path.exists(log_dir):
        os.makedirs(log_dir)
    log_filename = log_dir + '\\' + log_filename
    #每次运行会清空上次运行生成的日志文件，若需保留每次运行的日志，可删除下面if语句
    if os.path.exists(log_filename):
        pass
        #os.remove(log_filename)
    # 一个日志50M, 超过 app.log 指定的大小会自动滚动创建日志文件  app.log.1, app.log.2, app.log.3
    fp = logging.handlers.RotatingFileHandler(log_filename, maxBytes=1024 * 1024 * 50,
                                              backupCount=30, encoding='utf-8')
    # 再创建一个handler，用于输出到控制台
    fs = logging.StreamHandler()
    logging.basicConfig(level=logging.INFO, format=LOG_FORMAT, datefmt=DATE_FORMAT,
                        handlers=[fp, fs])
    def __init__(self):
        pass
    def LogInfo(self, var: any):
        logging.info(var)
    def LogWarning(self, var: any):
        logging.warning(var)
    def LogError(self, var: any):
        logging.error(var)

def getSheets(target_excel_file_path):
    #获取表格sheet，此处不做数据处理
    if target_excel_file_path is not None:
        #新建字典用于存储对应sheet
        target_excel_file_sheets = {}
        Log().LogInfo('Data Import Succeeded')
        Log().LogInfo(f'It Will Takes a Few Minutes To Loading Current Excel File Sheets : "{target_excel_file_path}"')
        #导入表格：表格内容较多时，该库导入速度较慢。待优化。
        target_excel_file = openpyxl.load_workbook(os.path.abspath(target_excel_file_path),read_only=False)
        #获取excel文件内所有表格名
        target_excel_file_sheet_names = target_excel_file.sheetnames
        Log().LogInfo(f'Current Excel File Sheets Loaded Successful: "{target_excel_file_sheet_names}"')
        for item in target_excel_file_sheet_names:
            #该字典键为sheet名，值为sheet具体内容
            target_excel_file_sheets.update({item: target_excel_file.get_sheet_by_name(item)})
        target_excel_file.close()
        return target_excel_file_sheets
        
def contains(var1: any, var2: str):
    if var1 is None or var2 is None:
        return False
    if isinstance(var1, str):
        return var1.lower().__contains__(var2.lower())
    elif isinstance(var1, list):
        return var1.__contains__(var2)
    elif isinstance(var1, dict):
        return var1.keys().__contains__(var2)

def rmPreSuffix(data: str):
    if data.__contains__('_'):
        data = copy.deepcopy(data.removeprefix('_'))
        data = copy.deepcopy(data.removesuffix('_'))
    return data
       
def get_table_headers(sheet,row_index):
    #sheet为输入sheet,row_index为表头所在行
    #获取sheet内对应的表头信息，注意表头需连续，不许存在表头之间存在空列
    #否则导致空列后面的表头信息一律不读取
    result = {}
    col = 'A'
    while sheet['%s%d' % (col, row_index)].value:#判断该列表头是否为空
        value = sheet['%s%d' % (col, row_index)].value
        while isinstance(value, str) and contains(value, '\n'):
            value = copy.deepcopy(value.replace('\n', ''))
        result[col] = value
        col = chr(ord(col) + 1)
    return result

def availability_check(var):
    #表格字符有效性检查，不能只为特殊符号如‘\’,'-',空格等
    if not var:
        return None
    else:
        availability_num = 0
        for tem in str(var):
            ###判断字符有效性，数字，英文，中文
            if str.isalnum(tem) or '\u4e00' <= tem<= '\u9fff':
                availability_num += 1
        if availability_num == 0:
            return None
        else:
            return var
        




